﻿// <copyright file="ValueConverters.cs" company="Oleg V. Polikarpotchkin">
// Copyright © 2008-2009 Oleg V. Polikarpotchkin. All Right Reserved
// </copyright>
// <author>Oleg V. Polikarpotchkin</author>
// <email>ov-p@yandex.ru</email>
// <date>2009-05-10</date>
// <summary>OpenWPFChart library. Helpers project value converters.</summary>
// <revision>$Id$</revision>

using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using OpenWPFChart.Parts;

namespace OpenWPFChart.Helpers
{
	/// <summary>
	/// Converts an Integer value to a Visibility.
	/// </summary>
	/// <remarks>
	/// This converter treats the input value as an integer. If it isn't the 
	/// <see cref="P:IntegerToVisibilityConverter.ParameterMatchTreatment"/> returned.
	/// <para>The converter converts the "parameter" value to <c>long</c>. If the "parameter"
	/// is <c>null</c> or is the convertion fails the parameter value regarded equal to zero.</para>
	/// <para>The input value is compared with the parameter value and if they are equal the
	/// <see cref="P:IntegerToVisibilityConverter.ParameterMatchTreatment"/> returned;
	/// otherwise <see cref="P:IntegerToVisibilityConverter.ParameterMismatchTreatment"/> returned.</para>
	/// <para>Partially borrowed from Mark Jumar 
	/// <a href="http://www.julmar.com/blog/mark/PermaLink,guid,8b3e4279-70a5-431e-8fa3-4c1e047df311.aspx">
	/// Julmar.Wpf.Helpers</a></para>
	/// </remarks>
	[ValueConversion(/*sourceType*/ typeof(int), /*targetType*/ typeof(Visibility))]
	public class IntegerToVisibilityConverter : IValueConverter
	{
		/// <summary>
		/// Mapping the match with the parameter value or the zero to Visibility.
		/// </summary>
		/// <remarks>
		/// Defaults to Collapsed.
		/// </remarks>
		public Visibility ParameterMatchTreatment { get; set; }
		/// <summary>
		/// Mapping the mismatch with the parameter value or the zero to Visibility.
		/// </summary>
		/// <remarks>
		/// Defaults to Visible.
		/// </remarks>
		public Visibility ParameterMismatchTreatment { get; set; }

		/// <summary>
		/// Initializes a new instance of the <see cref="IntegerToVisibilityConverter"/> class.
		/// </summary>
		public IntegerToVisibilityConverter()
		{
			ParameterMatchTreatment = Visibility.Collapsed;
			ParameterMismatchTreatment = Visibility.Visible;
		}

		#region IValueConverter Members
		/// <summary>
		/// Converts an Integer value to Visibility.
		/// </summary>
		/// <param name="value">The value produced by the binding source.</param>
		/// <param name="targetType">The type of the binding target property.</param>
		/// <param name="parameter">Provides the value to compare with the <paramref name="value"/>.
		/// Can be <c>null</c>.</param>
		/// <param name="culture"><see cref="M:System.Convert.ToInt64"/> convertion culture.</param>
		/// <returns>
		/// Either <see cref="P:IntegerToVisibilityConverter.ParameterMatchTreatment"/> or
		/// <see cref="P:IntegerToVisibilityConverter.ParameterMismatchTreatment"/> value.
		/// </returns>
		/// <remarks>
		/// This method treats the input value as an integer. If it isn't the 
		/// <see cref="P:IntegerToVisibilityConverter.ParameterMatchTreatment"/> returned.
		/// <para>The converter converts the <paramref name="parameter"/> value to <c>long</c>. 
		/// If the <paramref name="parameter"/> is <c>null</c> or if the convertion fails the 
		/// parameter value is treatewd as zero.</para>
		/// <para>The input <paramref name="value"/> is compared with the parameter value and if 
		/// they are equal the
		/// <see cref="P:IntegerToVisibilityConverter.ParameterMatchTreatment"/> returned;
		/// otherwise <see cref="P:IntegerToVisibilityConverter.ParameterMismatchTreatment"/> returned.</para>
		/// </remarks>
		public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			if (targetType != typeof(Visibility))
				return value;
			if (value == null || value == DependencyProperty.UnsetValue)
				return ParameterMatchTreatment;
			// Get the  parameter as long.
			long param = 0L;
			if (parameter != null)
			{
				try
				{
					param = System.Convert.ToInt64(parameter, culture);
				}
				catch (InvalidCastException)
				{
				}
			}
			// Convert value to Visibility.
			try
			{
				long n = System.Convert.ToInt64(value, culture);
				return n == param ? ParameterMatchTreatment : ParameterMismatchTreatment;
			}
			catch (InvalidCastException)
			{
			}

			return ParameterMatchTreatment;
		}

		/// <summary>
		/// Converts a value.
		/// </summary>
		/// <param name="value">The value that is produced by the binding target.</param>
		/// <param name="targetType">The type to convert to.</param>
		/// <param name="parameter">The converter parameter to use.</param>
		/// <param name="culture">The culture to use in the converter.</param>
		/// <returns>
		/// A converted value. If the method returns null, the valid null value is used.
		/// </returns>
		public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			throw new NotImplementedException();
		}
		#endregion IValueConverter Members
	}
	
	/// <summary>
	/// Converts an Integer value to bool.
	/// </summary>
	/// <remarks>
	/// This converter treats the input value as an integer. If it isn't the <c>false</c> is returned.
	/// <para>The converter converts the "parameter" value to <c>long</c>. If the "parameter"
	/// is <c>null</c> or is the convertion fails the parameter value regarded equal to zero.</para>
	/// <para>The input value is compared with the parameter value and if they are equal the
	/// <c>true</c> returned; otherwise the <c>false</c> is returned.</para>
	/// </remarks>
	[ValueConversion(/*sourceType*/ typeof(int), /*targetType*/ typeof(bool))]
	public class IntegerToBoolConverter : IValueConverter
	{
		#region IValueConverter Members
		/// <summary>
		/// Converts an Integer value to bool.
		/// </summary>
		/// <param name="value">The value produced by the binding source.</param>
		/// <param name="targetType">The type of the binding target property.</param>
		/// <param name="parameter">Provides the value to compare with the <paramref name="value"/>.
		/// Can be <c>null</c>.</param>
		/// <param name="culture"><see cref="M:System.Convert.ToInt64"/> convertion culture.</param>
		/// <returns>
		/// <c>false</c> if the input <paramref name="value"/> is equal to the <paramref name="parameter"/>
		/// or the <paramref name="parameter"/> is <c>null</c>; otherwise <c>true</c>.
		/// </returns>
		public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			if (targetType != typeof(bool))
				return value;
			if (value == null || value == DependencyProperty.UnsetValue)
				return false;
			// Get the  parameter as long.
			long param = 0L;
			if (parameter != null)
			{
				try
				{
					param = System.Convert.ToInt64(parameter, culture);
				}
				catch (InvalidCastException)
				{
				}
			}
			try
			{
				long n = System.Convert.ToInt64(value, culture);
				return n == param ? false : true;
			}
			catch (InvalidCastException)
			{
			}
			return false;
		}

		/// <summary>
		/// Converts a value.
		/// </summary>
		/// <param name="value">The value that is produced by the binding target.</param>
		/// <param name="targetType">The type to convert to.</param>
		/// <param name="parameter">The converter parameter to use.</param>
		/// <param name="culture">The culture to use in the converter.</param>
		/// <returns>
		/// A converted value. If the method returns null, the valid null value is used.
		/// </returns>
		public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			throw new NotImplementedException();
		}
		#endregion IValueConverter Members
	}

	/// <summary>
	/// Extracts the description from the <see cref="Type"/> given.
	/// </summary>
	[ValueConversion(typeof(Type), typeof(string))]
	public class InterpolatedVisualDescrptionConverter : IValueConverter
	{
		#region IValueConverter Members
		/// <summary>
		/// Extracts the description from the <see cref="Type"/> given.
		/// </summary>
		/// <param name="value">The value.</param>
		/// <param name="targetType">Type of the target.</param>
		/// <param name="parameter">Not used.</param>
		/// <param name="culture">Not used.</param>
		/// <returns>
		/// If the <paramref name="targetType"/> isn't the <see cref="Type"/> returns the
		/// input <paramref name="value"/>. Else if the <paramref name="value"/> is the <see cref="Type"/>
		/// which is decorated with the <see cref="InterpolatedAttribute"/> returns the
		/// <see cref="InterpolatedAttribute.Description"/> property value.
		/// </returns>
		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			if (!(value is Type))
				return value;
			Type type = value as Type;
			object[] attributes = type.GetCustomAttributes(typeof(InterpolatedAttribute), false);
			if (attributes.Length == 0)
				return value;
			InterpolatedAttribute attr = attributes[0] as InterpolatedAttribute;
			if (attr == null)
				return value;
			return string.IsNullOrEmpty(attr.Description) ? "Unknown" : attr.Description;
		}

		/// <summary>
		/// Converts a value.
		/// </summary>
		/// <param name="value">The value that is produced by the binding target.</param>
		/// <param name="targetType">The type to convert to.</param>
		/// <param name="parameter">The converter parameter to use.</param>
		/// <param name="culture">The culture to use in the converter.</param>
		/// <returns>
		/// A converted value. If the method returns null, the valid null value is used.
		/// </returns>
		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			throw new NotImplementedException();
		}

		#endregion IValueConverter Members
	}
	
	/// <summary>
	/// Extracts the <see cref="ChartScaleGroupAttribute.ClassDescription"/>ClassDescription property 
	/// value from the <see cref="ChartScaleGroupAttribute"/> attribute adorning the type.
	/// </summary>
	[ValueConversion(/*sourceType*/ typeof(Type), /*targetType*/ typeof(string))]
	public class ChartScaleGroupTypeToClassDescriptionConverter : IValueConverter
	{
		/// <summary>
		/// Extracts the <see cref="ChartScaleGroupAttribute.ClassDescription"/> 
		/// property value from the <see cref="ChartScaleGroupAttribute"/> attribute adorning the type.
		/// </summary>
		/// <param name="value">The value produced by the binding source.</param>
		/// <param name="targetType">The type of the binding target property.</param>
		/// <param name="parameter">Not used.</param>
		/// <param name="culture">Not used.</param>
		/// <returns>
		/// This method attempts to retrieve the <see cref="ChartScaleGroupAttribute"/> from the
		/// type provided as <paramref name="value"/>. If it fails to do that it returns the input
		/// <paramref name="value"/>; otherwise it returns the value of 
		/// <see cref="ChartScaleGroupAttribute.ClassDescription"/> property.
		/// </returns>
		public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			Type type = value as Type;
			if (type == null || !type.IsDefined(typeof(ChartScaleGroupAttribute), false))
				return value;
			object[] attributes = type.GetCustomAttributes(typeof(ChartScaleGroupAttribute), false);
			if (attributes == null || attributes.Length != 1 || !(attributes[0] is ChartScaleGroupAttribute))
				return value;
			ChartScaleGroupAttribute attribute = attributes[0] as ChartScaleGroupAttribute;
			if (attribute == null)
				return value;
			return attribute.ClassDescription;
		}

		/// <summary>
		/// Converts a value.
		/// </summary>
		/// <param name="value">The value that is produced by the binding target.</param>
		/// <param name="targetType">The type to convert to.</param>
		/// <param name="parameter">The converter parameter to use.</param>
		/// <param name="culture">The culture to use in the converter.</param>
		/// <returns>
		/// A converted value. If the method returns null, the valid null value is used.
		/// </returns>
		public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			throw new NotImplementedException();
		}
	}
}
